package cn.bugstack.http;

import cn.bugstack.IRAGService;
import cn.bugstack.response.Response;
import com.sun.istack.NotNull;
import jakarta.annotation.Resource;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider;
import org.redisson.api.RList;
import org.redisson.api.RSet;
import org.redisson.api.RedissonClient;
import org.springframework.ai.document.Document;
import org.springframework.ai.ollama.OllamaChatClient;
import org.springframework.ai.reader.tika.TikaDocumentReader;
import org.springframework.ai.transformer.splitter.TokenTextSplitter;
import org.springframework.ai.vectorstore.PgVectorStore;
import org.springframework.ai.vectorstore.SimpleVectorStore;
import org.springframework.core.io.PathResource;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.ArrayList;
import java.util.List;

/**
 * @Classname RAGController
 * @Description TODO
 * @Date 2025/10/16 14:50
 * @Author 勾新杰
 */
@Slf4j
@RestController
@CrossOrigin(origins = "*")
@RequestMapping("/api/v1/rag/")
public class RAGController implements IRAGService {

    @Resource
    private TokenTextSplitter tokenTextSplitter;

    @Resource
    private PgVectorStore pgVectorStore;

    @Resource
    private RedissonClient redissonClient;

    /**
     * 查询标签列表
     *
     * @return 响应
     */
    @Override
    @RequestMapping(value = "/queryRAGTagList", method = RequestMethod.GET)
    public Response<List<String>> queryRAGTagList() {
        RSet<String> set = redissonClient.getSet("ragTag");
        return Response.<List<String>>builder()
                .code("0000")
                .msg("调用成功")
                .data(new ArrayList<>(set)).build();
    }

    /**
     * 上传文件
     *
     * @param ragTag 标签
     * @param files  文件
     * @return 响应
     */
    @Override
    @RequestMapping(value = "/uploadFile", method = RequestMethod.POST, consumes = "multipart/form-data")
    public Response<String> uploadFile(@RequestParam String ragTag, @RequestPart("file") List<MultipartFile> files) {
        log.info("上传知识库文件开始");
        for (MultipartFile file : files) {
            TikaDocumentReader tikaDocumentReader = new TikaDocumentReader(file.getResource());
            saveToPgVector(tikaDocumentReader, ragTag);
            RSet<String> set = redissonClient.getSet("ragTag");
            set.add(ragTag);
        }
        log.info("上传知识库文件结束");
        return Response.<String>builder().code("0000").msg("调用成功").build();
    }

    /**
     * 分析Git仓库
     *
     * @param repoUrl  仓库地址
     * @param username 用户名
     * @param token    令牌
     * @return 响应
     */
    @Override
    @RequestMapping(value = "/analyzeGitRepository", method = RequestMethod.POST)
    public Response<String> analyzeGitRepository(@RequestParam String repoUrl, @RequestParam String username, @RequestParam String token) throws IOException, GitAPIException {
        String localPath = "./git-cloned-repo";
        String repoProjectName = extractProjectName(repoUrl);
        log.info("克隆路径：{}", new File(localPath).getAbsolutePath());

        FileUtils.deleteDirectory(new File(localPath));
        Git git = Git.cloneRepository()
                .setURI(repoUrl)
                .setDirectory(new File(localPath))
                .setCredentialsProvider(new UsernamePasswordCredentialsProvider(username, token))
                .call();

        Files.walkFileTree(Paths.get(localPath), new SimpleFileVisitor<>() {
            @NonNull
            @Override
            public FileVisitResult visitFile(Path file, @NonNull BasicFileAttributes attrs) throws IOException {
                log.info("{} 遍历解析路径，上传知识库:{}", repoProjectName, file.getFileName());
                try {
                    TikaDocumentReader reader = new TikaDocumentReader(new PathResource(file));
                    saveToPgVector(reader, repoProjectName);
                } catch (Exception e) {
                    log.error("遍历解析路径，上传知识库失败:{}", file.getFileName());
                }
                return FileVisitResult.CONTINUE;
            }

            @NonNull
            @Override
            public FileVisitResult visitFileFailed(Path file, @NonNull IOException e) throws IOException {
                log.info("Failed to access file: {} - {}", file.toString(), e.getMessage());
                return FileVisitResult.CONTINUE;
            }
        });

        RSet<Object> set = redissonClient.getSet("ragTag");
        set.add(repoProjectName);

        FileUtils.deleteDirectory(new File(localPath));
        git.close();
        log.info("遍历解析路径，上传完成:{}", repoUrl);

        return Response.<String>builder().code("0000").msg("调用成功").build();
    }

    /**
     * 保存到向量库
     *
     * @param reader          读取器
     * @param repoProjectName 项目名称
     */
    private void saveToPgVector(TikaDocumentReader reader, String repoProjectName) {
        List<Document> documents = reader.get();
        List<Document> documentSplitterList = tokenTextSplitter.apply(documents);

        documents.forEach(doc -> doc.getMetadata().put("knowledge", repoProjectName));
        documentSplitterList.forEach(doc -> doc.getMetadata().put("knowledge", repoProjectName));

        pgVectorStore.accept(documentSplitterList);
    }

    /**
     * 提取项目名
     *
     * @param repoUrl 仓库地址
     * @return 项目名
     */
    private String extractProjectName(String repoUrl) {
        String[] parts = repoUrl.split("/");
        String projectNameWithGit = parts[parts.length - 1];
        return projectNameWithGit.replace(".git", "");
    }
}
